home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / zip.zip / ZIPSPLIT.C < prev    next >
C/C++ Source or Header  |  1992-09-22  |  17KB  |  572 lines

  1. /*
  2.  
  3.  Copyright (C) 1990,1991 Mark Adler, Richard B. Wales, and Jean-loup Gailly.
  4.  Permission is granted to any individual or institution to use, copy, or
  5.  redistribute this software so long as all of the original files are included
  6.  unmodified, that it is not sold for profit, and that this copyright notice
  7.  is retained.
  8.  
  9. */
  10.  
  11. /*
  12.  *  zipsplit.c by Mark Adler.
  13.  */
  14.  
  15. #define UTIL
  16. #include "revision.h"
  17. #include "zip.h"
  18. #include <signal.h>
  19.  
  20. #define DEFSIZ 36000L   /* Default split size (change in help() too) */
  21. #ifdef MSDOS
  22. #  define NL 2          /* Number of bytes written for a \n */
  23. #else /* !MSDOS */
  24. #  define NL 1          /* Number of bytes written for a \n */
  25. #endif /* ?MSDOS */
  26. #define INDEX "zipsplit.idx"    /* Name of index file */
  27.  
  28.  
  29. /* Local functions */
  30. #ifdef PROTO
  31.    local void err(int, char *);
  32.    local void handler(int);
  33.    local void license(void);
  34.    local void help(void);
  35.    local extent simple(ulg *, extent, ulg, ulg);
  36.    local int descmp(voidp *, voidp *);
  37.    local extent greedy(ulg *, extent, ulg, ulg);
  38.    void main(int, char **);
  39. #endif /* PROTO */
  40.  
  41.  
  42. /* Output zip files */
  43. local char template[16];        /* name template for output files */
  44. local int zipsmade = 0;         /* number of zip files made */
  45. local int indexmade = 0;        /* true if index file made */
  46. local char *path = NULL;        /* space for full name */
  47. local char *name;               /* where name goes in path[] */
  48.  
  49.  
  50. local void err(c, h)
  51. int c;                  /* error code from the ZE_ class */
  52. char *h;                /* message about how it happened */
  53. /* Issue a message for the error, clean up files and memory, and exit. */
  54. {
  55.   if (PERR(c))
  56.     perror("zipsplit error");
  57.   fprintf(stderr, "zipsplit error: %s (%s)\n", errors[c-1], h);
  58.   if (indexmade)
  59.   {
  60.     strcpy(name, INDEX);
  61.     destroy(path);
  62.   }
  63.   for (; zipsmade; zipsmade--)
  64.   {
  65.     sprintf(name, template, zipsmade);
  66.     destroy(path);
  67.   }
  68.   if (path != NULL)
  69.     free((voidp *)path);
  70.   if (zipfile != NULL)
  71.     free((voidp *)zipfile);
  72. #ifdef VMS
  73.   exit(0);
  74. #else /* !VMS */
  75.   exit(c);
  76. #endif /* ?VMS */
  77. }
  78.  
  79.  
  80.  
  81. local void handler(s)
  82. int s;                  /* signal number (ignored) */
  83. /* Upon getting a user interrupt, abort cleanly using err(). */
  84. {
  85. #ifndef MSDOS
  86.   putc('\n', stderr);
  87. #endif /* !MSDOS */
  88.   err(ZE_ABORT, "aborting");
  89.   s++;                                  /* keep some compilers happy */
  90. }
  91.  
  92.  
  93. void warn(a, b)
  94. char *a, *b;            /* message strings juxtaposed in output */
  95. /* Print a warning message to stderr and return. */
  96. {
  97.   fprintf(stderr, "zipsplit warning: %s%s\n", a, b);
  98. }
  99.  
  100.  
  101. local void license()
  102. /* Print license information to stdout. */
  103. {
  104.   extent i;             /* counter for copyright array */
  105.  
  106.   for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
  107.     puts(copyright[i]);
  108.   for (i = 0; i < sizeof(disclaimer)/sizeof(char *); i++)
  109.     puts(disclaimer[i]);
  110. }
  111.  
  112.  
  113. local void help()
  114. /* Print help (along with license info) to stdout. */
  115. {
  116.   extent i;             /* counter for help array */
  117.  
  118.   /* help array */
  119.   static char *text[] = {
  120. "",
  121. "ZipSplit %d.%d (%s)",
  122. "Usage:  zipsplit [-ti] [-n size] [-b path] zipfile",
  123. "  -t   report how many files it will take, but don't make them",
  124. "  -i   make index (zipsplit.idx) and count its size against first zip file",
  125. "  -n   make zip files no larger than \"size\" (default = 36000)",
  126. "  -b   use \"path\" for the output zip files",
  127. "  -s   do a sequential split even if it takes more zip files",
  128. "  -h   show this help               -l   show software license"
  129.   };
  130.  
  131.   for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
  132.     puts(copyright[i]);
  133.   for (i = 0; i < sizeof(text)/sizeof(char *); i++)
  134.   {
  135.     printf(text[i], REVISION / 10, REVISION % 10, REVDATE);
  136.     putchar('\n');
  137.   }
  138. }
  139.  
  140.  
  141. local extent simple(a, n, c, d)
  142. ulg *a;         /* items to put in bins, return value: destination bins */
  143. extent n;       /* number of items */
  144. ulg c;          /* capacity of each bin */
  145. ulg d;          /* amount to deduct from first bin */
  146. /* Return the number of bins of capacity c that are needed to contain the
  147.    integers in a[0..n-1] placed sequentially into the bins.  The value d
  148.    is deducted initially from the first bin (space for index).  The entries
  149.    in a[] are replaced by the destination bins. */
  150. {
  151.   extent k;     /* current bin number */
  152.   ulg t;        /* space used in current bin */
  153.  
  154.   t = k = 0;
  155.   while (n--)
  156.   {
  157.     if (*a + t > c - (k == 0 ? d : 0))
  158.     {
  159.       k++;
  160.       t = 0;
  161.     }
  162.     t += *a;
  163.     *(ulg huge *)a++ = k;
  164.   }
  165.   return k + 1;
  166. }
  167.  
  168.  
  169. local int descmp(a, b)
  170. voidp *a, *b;           /* pointers to pointers to ulg's to compare */
  171. /* Used by qsort() in greedy() to do a descending sort. */
  172. {
  173.   return **(ulg **)a < **(ulg **)b ? 1 : (**(ulg **)a > **(ulg **)b ? -1 : 0);
  174. }
  175.  
  176.  
  177. local extent greedy(a, n, c, d)
  178. ulg *a;         /* items to put in bins, return value: destination bins */
  179. extent n;       /* number of items */
  180. ulg c;          /* capacity of each bin */
  181. ulg d;          /* amount to deduct from first bin */
  182. /* Return the number of bins of capacity c that are needed to contain the
  183.    items with sizes a[0..n-1] placed non-sequentially into the bins.  The
  184.    value d is deducted initially from the first bin (space for index).
  185.    The entries in a[] are replaced by the destination bins. */
  186. {
  187.   ulg *b;       /* space left in each bin (malloc'ed for each m) */
  188.   ulg *e;       /* copy of argument a[] (malloc'ed) */
  189.   extent i;     /* steps through items */
  190.   extent j;     /* steps through bins */
  191.   extent k;     /* best bin to put current item in */
  192.   extent m;     /* current number of bins */
  193.   ulg **s;      /* pointers to e[], sorted descending (malloc'ed) */
  194.   ulg t;        /* space left in best bin (index k) */
  195.  
  196.   /* Algorithm:
  197.      1. Copy a[] to e[] and sort pointers to e[0..n-1] (in s[]), in
  198.         descending order.
  199.      2. Compute total of s[] and set m to the smallest number of bins of
  200.         capacity c that can hold the total.
  201.      3. Allocate m bins.
  202.      4. For each item in s[], starting with the largest, put it in the
  203.         bin with the smallest current capacity greater than or equal to the
  204.         item's size.  If no bin has enough room, increment m and go to step 4.
  205.      5. Else, all items ended up in a bin--return m.
  206.   */
  207.  
  208.   /* Copy a[] to e[], put pointers to e[] in s[], and sort s[].  Also compute
  209.      the initial number of bins (minus 1). */
  210.   if ((e = (ulg *)malloc(n * sizeof(ulg))) == NULL ||
  211.       (s = (ulg **)malloc(n * sizeof(ulg *))) == NULL)
  212.   {
  213.     if (e != NULL)
  214.       free((voidp *)e);
  215.     err(ZE_MEM, "was trying a smart split");
  216.     return 0;                           /* only to make compiler happy */
  217.   }
  218.   memcpy((char *)e, (char *)a, n * sizeof(ulg));
  219.   for (t = i = 0; i < n; i++)
  220.     t += *(s[i] = e + i);
  221.   m = (extent)((t + c - 1) / c) - 1;    /* pre-decrement for loop */
  222.   qsort((char *)s, n, sizeof(ulg *), descmp);
  223.  
  224.   /* Stuff bins until successful */
  225.   do {
  226.     /* Increment the number of bins, allocate and initialize bins */
  227.     if ((b = (ulg *)malloc(++m * sizeof(ulg))) == NULL)
  228.     {
  229.       free((voidp *)s);
  230.       free((voidp *)e);
  231.       err(ZE_MEM, "was trying a smart split");
  232.     }
  233.     b[0] = c - d;                       /* leave space in first bin */
  234.     for (j = 1; j < m; j++)
  235.       b[j] = c;
  236.  
  237.     /* Fill the bins greedily */
  238.     for (i = 0; i < n; i++)
  239.     {
  240.       /* Find smallest bin that will hold item i (size s[i]) */
  241.       t = c + 1;
  242.       for (k = j = 0; j < m; j++)
  243.         if (*s[i] <= b[j] && b[j] < t)
  244.           t = b[k = j];
  245.  
  246.       /* If no bins big enough for *s[i], try next m */
  247.       if (t == c + 1)
  248.         break;
  249.  
  250.       /* Diminish that bin and save where it goes */
  251.       b[k] -= *s[i];
  252.       a[(int)((ulg huge *)(s[i]) - (ulg huge *)e)] = k;
  253.     }
  254.  
  255.     /* Clean up */
  256.     free((voidp *)b);
  257.  
  258.     /* Do until all items put in a bin */
  259.   } while (i < n);
  260.  
  261.   /* Done--clean up and return the number of bins needed */
  262.   free((voidp *)s);
  263.   free((voidp *)e);
  264.   return m;
  265. }
  266.  
  267.  
  268. void main(argc, argv)
  269. int argc;               /* number of tokens in command line */
  270. char **argv;            /* command line tokens */
  271. /* Split a zip file into several zip files less than a specified size.  See
  272.    the command help in help() above. */
  273. {
  274.   ulg *a;               /* malloc'ed list of sizes, dest bins */
  275.   extent *b;            /* heads of bin linked lists (malloc'ed) */
  276.   ulg c;                /* bin capacity, start of central directory */
  277.   int d;                /* if true, just report the number of disks */
  278.   FILE *e;              /* input zip file */
  279.   FILE *f;              /* output index and zip files */
  280.   extent g;             /* number of bins from greedy(), entry to write */
  281.   int h;                /* how to split--true means simple split, counter */
  282.   ulg i;                /* size of index file or zero if none */
  283.   extent j;             /* steps through zip entries, bins */
  284.   int k;                /* next argument type */
  285.   ulg *p;               /* malloc'ed list of sizes, dest bins for greedy() */
  286.   char *q;              /* steps through option characters */
  287.   int r;                /* temporary variable, counter */
  288.   extent s;             /* number of bins needed */
  289.   ulg t;                /* total of sizes, end of central directory */
  290.   struct zlist far **w; /* malloc'ed table for zfiles linked list */
  291.   int x;                /* if true, make an index file */
  292.   struct zlist far *z;  /* steps through zfiles linked list */
  293.  
  294.  
  295.   /* If no args, show help */
  296.   if (argc == 1)
  297.   {
  298.     help();
  299.     exit(0);
  300.   }
  301.  
  302.   /* Go through args */
  303.   signal(SIGINT, handler);
  304.   signal(SIGTERM, handler);
  305.   k = h = x = d = 0;
  306.   c = DEFSIZ;
  307.   for (r = 1; r < argc; r++)
  308.     if (*argv[r] == '-')
  309.       if (argv[r][1])
  310.         for (q = argv[r]+1; *q; q++)
  311.           switch(*q)
  312.           {
  313.             case 'b':   /* Specify path for output files */
  314.               if (k)
  315.                 err(ZE_PARMS, "options are separate and precede zip file");
  316.               else
  317.                 k = 1;          /* Next non-option is path */
  318.               break;
  319.             case 'h':   /* Show help */
  320.               help();  exit(0);
  321.             case 'i':   /* Make an index file */
  322.               x = 1;
  323.               break;
  324.             case 'l':   /* Show copyright and disclaimer */
  325.               license();  exit(0);
  326.             case 'n':   /* Specify maximum size of resulting zip files */
  327.               if (k)
  328.                 err(ZE_PARMS, "options are separate and precede zip file");
  329.               else
  330.                 k = 2;          /* Next non-option is size */
  331.               break;
  332.             case 's':
  333.               h = 1;    /* Only try simple */
  334.               break;
  335.             case 't':   /* Just report number of disks */
  336.               d = 1;
  337.               break;
  338.             default:
  339.               err(ZE_PARMS, "unknown option");
  340.           }
  341.       else
  342.         err(ZE_PARMS, "zip file cannot be stdin");
  343.     else
  344.       if (k == 0)
  345.         if (zipfile == NULL)
  346.         {
  347.           if ((zipfile = ziptyp(argv[r])) == NULL)
  348.             err(ZE_MEM, "was processing arguments");
  349.         }
  350.         else
  351.           err(ZE_PARMS, "can only specify one zip file");
  352.       else if (k == 1)
  353.       {
  354.         tempath = argv[r];
  355.         k = 0;
  356.       }
  357.       else              /* k must be 2 */
  358.       {
  359.         if ((c = (ulg)atol(argv[r])) < 100)     /* 100 is smallest zip file */
  360.           err(ZE_PARMS, "invalid size given");
  361.         k = 0;
  362.       }
  363.   if (zipfile == NULL)
  364.     err(ZE_PARMS, "need to specify zip file");
  365.  
  366.  
  367.   /* Read zip file */
  368.   if ((r = readzipfile()) != ZE_OK)
  369.     err(r, zipfile);
  370.   if (zfiles == NULL)
  371.     err(ZE_NAME, zipfile);
  372.  
  373.   /* Make a list of sizes and check against capacity.  Also compute the
  374.      size of the index file. */
  375.   c -= ENDHEAD + 4;                     /* subtract overhead/zipfile */
  376.   if ((a = (ulg *)malloc(zcount * sizeof(ulg))) == NULL ||
  377.       (w = (struct zlist far **)malloc(zcount * sizeof(struct zlist far *))) ==
  378.        NULL)
  379.   {
  380.     if (a != NULL)
  381.       free((voidp *)a);
  382.     err(ZE_MEM, "was computing split");
  383.     return;
  384.   }
  385.   i = t = 0;
  386.   for (j = 0, z = zfiles; j < zcount; j++, z = z->nxt)
  387.   {
  388.     w[j] = z;
  389.     if (x)
  390.       i += z->nam + 6 + NL;
  391.     t += a[j] = 8 + LOCHEAD + CENHEAD +
  392.            2 * (ulg)z->nam + 2 * (ulg)z->ext + z->com + z->siz;
  393.     if (a[j] > c)
  394.     {
  395.       free((voidp *)w);  free((voidp *)a);
  396.       err(ZE_BIG, z->zname);
  397.     }
  398.   }
  399.  
  400.   /* Decide on split to use, report number of files */
  401.   if (h)
  402.     s = simple(a, zcount, c, i);
  403.   else
  404.   {
  405.     if ((p = (ulg *)malloc(zcount * sizeof(ulg))) == NULL)
  406.     {
  407.       free((voidp *)w);  free((voidp *)a);
  408.       err(ZE_MEM, "was computing split");
  409.     }
  410.     memcpy((char *)p, (char *)a, zcount * sizeof(ulg));
  411.     s = simple(a, zcount, c, i);
  412.     g = greedy(p, zcount, c, i);
  413.     if (s <= g)
  414.       free((voidp *)p);
  415.     else
  416.     {
  417.       free((voidp *)a);
  418.       a = p;
  419.       s = g;
  420.     }
  421.   }
  422.   printf("%d zip files w%s be made (%d%% efficiency)\n",
  423.          s, d ? "ould" : "ill", ((200 * ((t + c - 1)/c)) / s + 1) >> 1);
  424.   if (d)
  425.   {
  426.     free((voidp *)w);  free((voidp *)a);
  427.     free((voidp *)zipfile);
  428.     zipfile = NULL;
  429.     return;
  430.   }
  431.  
  432.   /* Set up path for output files */
  433.   if ((path = malloc(tempath == NULL ? 13 : strlen(tempath) + 14)) == NULL)
  434.     err(ZE_MEM, "was making output file names");
  435.   if (tempath == NULL)
  436.      name = path;
  437.   else
  438.   {
  439.     strcpy(path, tempath);
  440.     if (path[0] && path[strlen(path) - 1] != '/')
  441.       strcat(path, "/");
  442.     name = path + strlen(path);
  443.   }
  444.  
  445.   /* Write the index file */
  446.   if (x)
  447.   {
  448.     strcpy(name, INDEX);
  449.     printf("creating %s\n", path);
  450.     indexmade = 1;
  451.     if ((f = fopen(path, "w")) == NULL)
  452.     {
  453.       free((voidp *)w);  free((voidp *)a);
  454.       err(ZE_CREAT, path);
  455.     }
  456.     for (j = 0; j < zcount; j++)
  457.       fprintf(f, "%5ld %s\n", a[j] + 1, w[j]->zname);
  458.     if ((j = ferror(f)) != 0 || fclose(f))
  459.     {
  460.       if (j)
  461.         fclose(f);
  462.       free((voidp *)w);  free((voidp *)a);
  463.       err(ZE_WRITE, path);
  464.     }
  465.   }
  466.  
  467.   /* Make linked lists of results */
  468.   if ((b = (extent *)malloc(s * sizeof(extent))) == NULL)
  469.   {
  470.     free((voidp *)w);  free((voidp *)a);
  471.     err(ZE_MEM, "was computing split");
  472.   }
  473.   for (j = 0; j < s; j++)
  474.     b[j] = -1;
  475.   j = zcount;
  476.   while (j--)
  477.   {
  478.     g = (extent)a[j];
  479.     a[j] = b[g];
  480.     b[g] = j;
  481.   }
  482.  
  483.   /* Make a name template for the zip files that is eight or less characters
  484.      before the .zip, and that will not overwrite the original zip file. */
  485.   for (k = 1, j = s; j >= 10; j /= 10)
  486.     k++;
  487.   if (k > 7)
  488.   {
  489.     free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
  490.     err(ZE_PARMS, "way too many zip files must be made");
  491.   }
  492.   if ((q = strrchr(zipfile, '/')) != NULL)
  493.     q++;
  494.   else
  495.     q = zipfile;
  496.   r = 0;
  497.   while ((g = *q++) != 0 && g != '.' && r < 8 - k)
  498.     template[r++] = (char)g;
  499.   if (r == 0)
  500.     template[r++] = '_';
  501.   else if (g >= '0' && g <= '9')
  502.     template[r - 1] = (char)(template[r - 1] == '_' ? '-' : '_');
  503.   sprintf(template + r, "%%0%dd.zip", k);
  504.  
  505.   /* Make the zip files from the linked lists of entry numbers */
  506.   if ((e = fopen(zipfile, FOPR)) == NULL)
  507.   {
  508.     free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
  509.     err(ZE_NAME, zipfile);
  510.   }
  511.   free((voidp *)zipfile);
  512.   zipfile = NULL;
  513.   for (j = 0; j < s; j++)
  514.   {
  515.     sprintf(name, template, j + 1);
  516.     printf("creating %s\n", path);
  517.     zipsmade = j + 1;
  518.     if ((f = fopen(path, FOPW)) == NULL)
  519.     {
  520.       free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
  521.       err(ZE_CREAT, path);
  522.     }
  523.     for (g = b[j]; g != (extent)-1; g = (extent)a[g])
  524.     {
  525.       if (fseek(e, w[g]->off, SEEK_SET))
  526.       {
  527.         free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
  528.         err(ferror(e) ? ZE_READ : ZE_EOF, zipfile);
  529.       }
  530.       if ((r = zipcopy(w[g], e, f)) != ZE_OK)
  531.       {
  532.         free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
  533.         if (r == ZE_TEMP)
  534.           err(ZE_WRITE, path);
  535.         else
  536.           err(r, zipfile);
  537.       }
  538.     }
  539.     if ((c = ftell(f)) == -1L)
  540.     {
  541.       free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
  542.       err(ZE_WRITE, path);
  543.     }
  544.     for (g = b[j], k = 0; g != (extent)-1; g = (extent)a[g], k++)
  545.       if ((r = putcentral(w[g], f)) != ZE_OK)
  546.       {
  547.         free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
  548.         err(ZE_WRITE, path);
  549.       }
  550.     if ((t = ftell(f)) == -1L)
  551.     {
  552.       free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
  553.       err(ZE_WRITE, path);
  554.     }
  555.     if ((r = putend(k, t - c, c, (extent)0, (char *)NULL, f)) != ZE_OK)
  556.     {
  557.       free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
  558.       err(ZE_WRITE, path);
  559.     }
  560.     if (ferror(f) || fclose(f))
  561.     {
  562.       free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
  563.       err(ZE_WRITE, path);
  564.     }
  565.   }
  566.   free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
  567.   fclose(e);
  568.  
  569.   /* Done! */
  570.   exit(0);
  571. }
  572.